home *** CD-ROM | disk | FTP | other *** search
/ Chip: Internet / Chip Internet.iso / viewer / ghost / display.c < prev    next >
C/C++ Source or Header  |  1993-08-05  |  18KB  |  696 lines

  1. /*
  2.  * display.c -- Ghostscript display operations for GSVIEW.EXE, 
  3.  *              a graphical interface for MS-Windows Ghostscript
  4.  * Copyright (C) 1993  Russell Lang
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   Author: Russell Lang
  21.  * Internet: rjl@monu1.cc.monash.edu.au
  22.  */
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commdlg.h>
  28. #include <shellapi.h>
  29. #include <mmsystem.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <dir.h>
  35. #include <io.h>
  36. #define NeedFunctionPrototypes 1
  37. #include "ps.h"
  38. #include "gsview.h"
  39.  
  40. struct ftime dftime;    /* time/date of selected file */
  41. long dflength;        /* length of selected file */
  42.  
  43. /* get current media index to papersizes[], or -1 if no match */
  44. int
  45. get_papersizes_index()
  46. {
  47. int i;
  48.     for (i=0; papersizes[i].name != (char *)NULL; i++) {
  49.         if (!stricmp(papersizes[i].name, medianame))
  50.         return i;
  51.     }
  52.     return -1;
  53. }
  54.  
  55. /* calculate bitmap size for gswin */
  56. void
  57. gswin_size()
  58. {
  59. int i = get_papersizes_index();
  60.     if ( (xdpi == 0.0) || (ydpi == 0.0) )
  61.         xdpi = ydpi = DEFAULT_RESOLUTION;
  62.     epsf_clipped = FALSE;
  63.     switch (orientation) {
  64.         case IDM_LANDSCAPE:
  65.         case IDM_SEASCAPE:
  66.         if (i < 0) {
  67.             bitmap_width = user_height;
  68.             bitmap_height = user_width;
  69.         }
  70.         else {
  71.             bitmap_width = papersizes[i].height;
  72.             bitmap_height = papersizes[i].width;
  73.         }
  74.         break;
  75.         default:
  76.         if ((doc != (struct document *)NULL) && doc->epsf
  77.             && epsf_clip) {
  78.             epsf_clipped = TRUE;
  79.             bitmap_width = doc->boundingbox[URX] - doc->boundingbox[LLX];
  80.             bitmap_height = doc->boundingbox[URY] - doc->boundingbox[LLY];
  81.         }
  82.         else if (i < 0) {
  83.             bitmap_width = user_width;
  84.             bitmap_height = user_height;
  85.         }
  86.         else {
  87.             bitmap_width = papersizes[i].width;
  88.             bitmap_height = papersizes[i].height;
  89.         }
  90.     }
  91.     bitmap_width  = (unsigned int)(bitmap_width  / 72.0 * xdpi);
  92.     bitmap_height = (unsigned int)(bitmap_height / 72.0 * ydpi);
  93. }
  94.  
  95. /* change the size of the gswin image if open */
  96. void
  97. gswin_resize()
  98. {
  99. BOOL display = FALSE;
  100. BOOL opened_dfile = FALSE;
  101.     gswin_size();
  102.     if (gswin_hinst == (HINSTANCE)NULL)
  103.         return;
  104.     if ( (dfile == (FILE *)NULL) && (doc != (struct document *)NULL) ) {
  105.         dfreopen();
  106.         opened_dfile = TRUE;
  107.     }
  108.     if (redisplay && page_ready && (doc != (struct document *)NULL))
  109.         display = TRUE;    /* redisplay page after resize */
  110.     gsview_endfile();
  111.     if (gswin_hinst != (HINSTANCE)NULL) {
  112.         fprintf(cfile,"mark /HWSize [%u %u]\r\n",bitmap_width,bitmap_height);
  113.         fprintf(cfile,"/HWResolution [%g %g]\r\n",xdpi,ydpi);
  114.         fprintf(cfile,"currentdevice putdeviceprops pop erasepage flushpage\r\n");
  115.         pipeflush();
  116.     }
  117.     if (display) {
  118.         if (gswin_hinst != (HINSTANCE)NULL)
  119.             gswin_open();    /* we need it open to redisplay */
  120.            fix_orientation(cfile);
  121.            dsc_header(cfile);
  122.         dsc_getpages(cfile,pagenum,pagenum);
  123.         pipeflush();
  124.     }
  125.  
  126.     if (opened_dfile)
  127.         dfclose();
  128. }
  129.  
  130. void
  131. gsview_orientation(int new_orientation)
  132. {
  133.     if (new_orientation == orientation)
  134.         return;
  135.     if (new_orientation == IDM_SWAPLANDSCAPE) {
  136.         swap_landscape = !swap_landscape;
  137.         if (swap_landscape) 
  138.             CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_CHECKED);
  139.         else
  140.             CheckMenuItem(hmenu, IDM_SWAPLANDSCAPE, MF_BYCOMMAND | MF_UNCHECKED);
  141.         if ((orientation != IDM_LANDSCAPE) && (orientation != IDM_SEASCAPE))
  142.             return;
  143.     }
  144.     else {
  145.         CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_UNCHECKED);
  146.         orientation = new_orientation;
  147.         CheckMenuItem(hmenu, orientation, MF_BYCOMMAND | MF_CHECKED);
  148.     }
  149.     gswin_resize();
  150.     return;
  151. }
  152.  
  153. void
  154. gsview_media(int new_media)
  155. {
  156.     if ( (new_media == media) && (new_media != IDM_USERSIZE) )
  157.         return;
  158.     CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_UNCHECKED);
  159.     media = new_media;
  160.     CheckMenuItem(hmenu, media, MF_BYCOMMAND | MF_CHECKED);
  161.     GetMenuString(hmenu, media, medianame, sizeof(medianame), MF_BYCOMMAND);
  162.     gswin_resize();
  163.     return;
  164. }
  165.  
  166. /* run Ghostscript for previewing document */
  167. /* return TRUE if ok, FALSE if error */
  168. BOOL
  169. gswin_open()
  170. {
  171. char command[256];
  172.     /* return if already open */
  173.     if ((gswin_hinst != (HINSTANCE)NULL) && IsWindow(hwndimgchild))
  174.         return TRUE;
  175.  
  176.     pipeinit();        /* so we wait for first request */
  177.     gswin_size();
  178.     sprintf(command,"%s %s -r%gx%g -g%ux%u -sGSVIEW=%u -",
  179.         szGSwin, safer ? "-dSAFER" : "", xdpi, ydpi, 
  180.                 bitmap_width, bitmap_height, (unsigned int)hwndimg);
  181.     if (strlen(command) > 126) {
  182.         info_wait(FALSE);
  183.         gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR);
  184.         gswin_hinst = (HINSTANCE)NULL;
  185.         return FALSE;
  186.     }
  187.     gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE);
  188.  
  189.     if (gswin_hinst < HINSTANCE_ERROR) {
  190.         info_wait(FALSE);
  191.         gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR);
  192.         gswin_hinst = (HINSTANCE)NULL;
  193.         return FALSE;
  194.     }
  195.     if (hwndtext == (HWND)NULL) {
  196.         /* we are running an incompatible version of Ghostscript */
  197.         hwndtext = FindWindow("BCEasyWin","Ghostscript");
  198.         if (hwndtext) {
  199.             SendMessage(hwndtext, WM_CHAR, 'q', 1L);
  200.             SendMessage(hwndtext, WM_CHAR, 'u', 1L);
  201.             SendMessage(hwndtext, WM_CHAR, 'i', 1L);
  202.             SendMessage(hwndtext, WM_CHAR, 't', 1L);
  203.             SendMessage(hwndtext, WM_CHAR, '\r', 1L);
  204.         }
  205.         hwndtext = (HWND)NULL;
  206.         hwndimgchild = (HWND)NULL;
  207.         gswin_hinst = (HINSTANCE)NULL;
  208.         clear_timer();
  209.         info_wait(FALSE);
  210.         gserror(IDS_WRONGGS, NULL, MB_ICONSTOP, SOUND_ERROR);
  211.         return FALSE;
  212.     }
  213.     saved = FALSE;
  214.  
  215.     /* wait for gswin to initialise */
  216.     if (set_timer(CLOSE_TIMEOUT))
  217.         EnableWindow(hwndimg, FALSE);
  218.     while (!is_pipe_done()&&  !bTimeout)
  219.         do_message();    /* wait for pipe data request from gswin */
  220.     clear_timer();
  221.     EnableWindow(hwndimg, TRUE);
  222.  
  223.     cfile = pipeopen();    /* open pipe to gswin */
  224.     BringWindowToTop(hwndimg);
  225.     SetFocus(hwndimg);    /* kludge: without this desktop gets focus */
  226.     return TRUE;
  227. }
  228.  
  229. /* close Ghostscript */
  230. BOOL
  231. gswin_close()
  232. {
  233. BOOL force = FALSE;
  234.     if (gswin_hinst == (HINSTANCE)NULL)
  235.         return TRUE;
  236.  
  237.     if (doc == (struct document*)NULL) {
  238.         /* we don't know how many pages remain so we must force an exit */
  239.         if (!is_pipe_done())
  240.         force = TRUE;
  241.     }
  242.     else {
  243.         if (page_ready)
  244.         next_page();
  245.     }
  246.  
  247.     if (!force) {
  248.         /* try to close Ghostscript cleanly */
  249.         pipeclose();
  250.         if (set_timer(CLOSE_TIMEOUT))
  251.         EnableWindow(hwndimg, FALSE);
  252.         while (GetModuleUsage(gswin_hinst) &&  !bTimeout)
  253.         do_message();    /* wait for gswin to close */
  254.         clear_timer();
  255.         EnableWindow(hwndimg, TRUE);
  256.     }
  257.     do_message();
  258.  
  259.     /* if still there try killing it a using a brute force method */
  260.     if (IsWindow(hwndtext)) {
  261.         if (is_win31) {
  262.             SendMessage(hwndtext, WM_CLOSE, 0, 0L);
  263.             if (IsWindow(hwndtext))
  264.             SendMessage(hwndtext, WM_CLOSE, 0, 0L);
  265.         }
  266.         else {
  267.             /* Windows 3.0 hangs if we use SendMessage */
  268.             PostMessage(hwndtext, WM_CLOSE, 0, 0L);
  269.             do_message();
  270.         }
  271.     }
  272.  
  273.     do_message();
  274.     gswin_hinst = (HINSTANCE)NULL;
  275.     hwndimgchild = (HWND)NULL;
  276.     hwndtext = (HWND)NULL;
  277.     bitmap_scrollx = bitmap_scrolly = 0;
  278.     page_ready = FALSE;
  279.     saved = FALSE;
  280.     pipeclose();
  281.     return TRUE;
  282. }
  283.  
  284. /* send a NEXT_PAGE message to Ghostscript */
  285. void
  286. next_page()
  287. {
  288. int i;
  289.     if (hwndimgchild && IsWindow(hwndimgchild)) {
  290.         SendMessage(hwndimgchild, WM_GSVIEW, NEXT_PAGE, 0L);
  291.         page_ready = FALSE;
  292.     }
  293.     do_message();    /* wait for Ghostscript to process message */
  294.     for (i=0; i<32; i++) {
  295.        /* Wait a bit for pipe contents after showpage to be read */
  296.        do_message();
  297.        if (is_pipe_done())
  298.         break;
  299.     }
  300. }
  301.  
  302. /* handle messages while we are waiting */
  303. void
  304. do_message()
  305. {
  306.     MSG msg;
  307.     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
  308.     if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  309.             TranslateMessage(&msg);
  310.             DispatchMessage(&msg);
  311.         }
  312.     }
  313. }
  314.  
  315.  
  316. /* end of file - get ready for new file */
  317. void
  318. gsview_endfile()
  319. {
  320.     info_wait(TRUE);
  321.     if (gswin_hinst == (HINSTANCE)NULL)
  322.         return;
  323.     if (!quick ||
  324.              ((doc == (struct document *)NULL) && !is_pipe_done())) {
  325.         gswin_close();
  326.         return;
  327.     }
  328.  
  329.     if (page_ready)
  330.         next_page();
  331.  
  332.     if ((saved) && (doc != (struct document *)NULL) && (doc->pages)) {
  333.         /* send trailer if needed */
  334.         pscopy(dfile, cfile, doc->begintrailer, doc->endtrailer);
  335.     }
  336.     if (saved) {
  337.         /* restore interpreter state */
  338.         fputs("gsview_cleanup\r\n",cfile);
  339.         fputs("gsview_save restore\r\n",cfile);
  340.     }
  341.     else
  342.         fputs("clear cleardictstack\r\n",cfile);
  343.     pipeflush();
  344.     saved = FALSE;
  345. }
  346.  
  347. /* open a new document */
  348. void
  349. gsview_openfile(char *filename)
  350. {
  351. int i;
  352.     pagenum = 1;
  353.     page_extra = 0;
  354.     if (dsc_scan(filename)) {
  355.         /* found DSC comments */
  356.         if (doc->orientation == PORTRAIT)
  357.         gsview_orientation(IDM_PORTRAIT);
  358.         if (doc->orientation == LANDSCAPE)
  359.         gsview_orientation(IDM_LANDSCAPE);
  360.         if (doc->default_page_media) {
  361.         char thismedia[20];
  362.         for (i=IDM_LETTER; i<IDM_USERSIZE; i++) {
  363.             GetMenuString(hmenu, i, thismedia, sizeof(thismedia), MF_BYCOMMAND);
  364.             if (!stricmp(thismedia, doc->default_page_media->name)) {
  365.                 gsview_media(i);
  366.                 break;
  367.             }
  368.         }
  369.         if (i == IDM_USERSIZE) {
  370.             gsview_media(IDM_USERSIZE);
  371.             user_width  = doc->default_page_media->width;
  372.             user_height = doc->default_page_media->height;
  373.         }
  374.         }
  375.     }
  376. }
  377.  
  378.  
  379. /* get filename then open new file for printing or extract */
  380. void 
  381. gsview_select()
  382. {
  383.     LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic));
  384.     if (GetOpenFileName(&ofn))
  385.         gsview_selectfile(szOFilename);
  386. }
  387.  
  388. /* open new file for printing or extract */
  389. void
  390. gsview_selectfile(char *filename)
  391. {
  392.     if (gswin_hinst != (HINSTANCE)NULL)
  393.         gsview_endfile();
  394.     while (*filename && *filename==' ')
  395.          filename++;
  396.     gsview_openfile(filename);
  397.     info_wait(FALSE);
  398. }
  399.  
  400. /* get filename then open a new document and display it */
  401. void 
  402. gsview_display()
  403. {
  404.     LoadString(phInstance, IDS_TOPICOPEN, szHelpTopic, sizeof(szHelpTopic));
  405.     if (GetOpenFileName(&ofn))
  406.         gsview_displayfile(szOFilename);
  407. }
  408.  
  409. /* open a new document and display it */
  410. void
  411. gsview_displayfile(char *filename)
  412. {
  413. char *p;
  414.     gsview_endfile();
  415.  
  416.     info_wait(TRUE);
  417.  
  418.     gsview_openfile(filename);
  419.     if (epsf_clipped ||
  420.          ((doc != (struct document *)NULL) && doc->epsf && epsf_clip))
  421.         gswin_resize();
  422.  
  423.     if (!gswin_open()) {
  424.         return;
  425.     }
  426.  
  427.     fix_orientation(cfile);
  428.     if (doc != (struct document *)NULL) {
  429.         /* found DSC comments */
  430.         dsc_header(cfile);
  431.         dsc_getpages(cfile,pagenum,pagenum);
  432.     }
  433.     else {
  434.         /* non conformant file - send unmodified */
  435.         fputs("(Displaying ",cfile);
  436.         for (p=filename; *p; p++) {
  437.         if (*p != '\\')
  438.             fputc(*p,cfile);
  439.         else
  440.             fputc('/',cfile);
  441.         }
  442.         fputs("\\n) print flush\r\n",cfile);
  443.         fputc('(',cfile);
  444.         for (p=filename; *p; p++) {
  445.         if (*p != '\\')
  446.             fputc(*p,cfile);
  447.         else
  448.             fputc('/',cfile);
  449.         }
  450.         fputs(") run flushpage\r\n",cfile);
  451.     }
  452.     
  453.     pipeflush();
  454. }
  455.  
  456.  
  457. void
  458. send_prolog(FILE *f, char *resource)
  459. {  
  460. HGLOBAL hglobal;
  461. LPSTR prolog;
  462.     hglobal = LoadResource(phInstance, FindResource(phInstance, resource, RT_RCDATA));
  463.     if ( (prolog = (LPSTR)LockResource(hglobal)) != (LPSTR)NULL) {
  464.         while (*prolog)
  465.             fputc(*prolog++, f);
  466.         FreeResource(hglobal);
  467.     }
  468. }
  469.  
  470.  
  471. /* add Ghostscript code to change orientation */
  472. void
  473. fix_orientation(FILE *f)
  474. {
  475. int real_orientation;
  476.     /* save interpreter state */
  477.     fputs("clear cleardictstack save /gsview_save exch def\r\n",f);
  478.     saved = TRUE;
  479.     /* provide epsf offset */
  480.     if (epsf_clipped)
  481.         fprintf(f,"/gsview_offset {%d %d translate} def\r\n",
  482.             -doc->boundingbox[LLX], -doc->boundingbox[LLY]);
  483.     else
  484.         fprintf(f,"/gsview_offset {} def\r\n");
  485.     real_orientation = orientation;
  486.     if (swap_landscape) {
  487.         if (orientation == IDM_LANDSCAPE)
  488.         real_orientation = IDM_SEASCAPE;
  489.         else if (orientation == IDM_SEASCAPE)
  490.         real_orientation = IDM_LANDSCAPE;
  491.     }
  492.     fprintf(f,"/gsview_landscape  %s def\r\n",
  493.         real_orientation == IDM_LANDSCAPE ? "true" : "false");
  494.     fprintf(f,"/gsview_upsidedown %s def\r\n",
  495.         real_orientation ==  IDM_UPSIDEDOWN ? "true" : "false");
  496.     fprintf(f,"/gsview_seascape   %s def\r\n",
  497.         real_orientation == IDM_SEASCAPE ? "true" : "false");
  498.     send_prolog(f, "gsview_orientation");
  499.     if (epsf_warn)
  500.         send_prolog(f, "gsview_epswarn");
  501. }
  502.  
  503. /* Create and open a scratch file with a given name prefix. */
  504. /* Write the actual file name at fname. */
  505. FILE *
  506. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  507. {    char *temp;
  508.     if ( (temp = getenv("TEMP")) == NULL )
  509.         *fname = 0;
  510.     else
  511.     {    strcpy(fname, temp);
  512.         /* Prevent X's in path from being converted by mktemp. */
  513.         for ( temp = fname; *temp; temp++ )
  514.             *temp = tolower(*temp);
  515.         if ( strlen(fname) && (fname[strlen(fname)-1] != '\\') )
  516.             strcat(fname, "\\");
  517.     }
  518.     strcat(fname, prefix);
  519.     strcat(fname, "XXXXXX");
  520.     mktemp(fname);
  521.     return fopen(fname, mode);
  522. }
  523.  
  524. /* reopen dfile */
  525. /* if dfile time/date or length has changed, kill gswin and rescan the file */
  526. BOOL
  527. dfreopen()
  528. {
  529. struct ftime thisftime;
  530. long thisflength;
  531.     if (doc == (struct document *)NULL)
  532.         return TRUE;
  533.     dfclose();
  534.     if (dfname[0] == '\0')
  535.         return TRUE;
  536.     if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) 
  537.             == (FILE *)NULL ) {
  538.         if (debug)
  539.             MessageBox(hwndimg, "file missing", "dfreopen", MB_OK);
  540.         dfname[0] = '\0';
  541.         return FALSE;
  542.     }
  543.     getftime(fileno(dfile), &thisftime);
  544.     thisflength = filelength(fileno(dfile));
  545.     if ( (thisflength != dflength) ||
  546.         memcmp(&thisftime, &dftime, sizeof(thisftime)) ) {
  547.         if (debug)
  548.             MessageBox(hwndimg, "file changed", "dfreopen", MB_OK);
  549.         /* file may have changed beyond recognition so we must kill gswin */
  550.         gswin_close();
  551.         if (dsc_scan(dfname))
  552.             if ( (dfile = fopen(efname[0] ? efname : dfname, "rb")) 
  553.                 == (FILE *)NULL ) {
  554.                 dfname[0] = '\0';
  555.                 return FALSE;
  556.             }
  557.     }
  558.     return TRUE;
  559. }
  560.  
  561. void
  562. dfclose()
  563. {
  564.     if (dfile != (FILE *)NULL)
  565.         fclose(dfile);
  566.     dfile = (FILE *)NULL;
  567. }
  568.  
  569. /* scan file for PostScript Document Structuring Conventions */
  570. /* return TRUE if valid DSC comments found */
  571. BOOL
  572. dsc_scan(char *filename)
  573. {
  574. unsigned char eps[4];
  575.     strcpy(dfname, filename);
  576.     dfclose();
  577.     if ((efname[0] != '\0') && !debug)
  578.         unlink(efname);
  579.     efname[0] = '\0';
  580.     if ( (dfile = fopen(dfname, "rb")) == (FILE *)NULL ) {
  581.         dfname[0] = '\0';
  582.         return FALSE;
  583.     }
  584.     getftime(fileno(dfile), &dftime);
  585.     dflength = filelength(fileno(dfile));
  586.     if (page_list.select)
  587.         free(page_list.select);
  588.     page_list.select = NULL;
  589.     if (doc)
  590.         psfree(doc);
  591.     is_ctrld = FALSE;
  592.     fread(eps, 1, 4, dfile);
  593.     if ((eps[0]==0xc5) && (eps[1]==0xd0) && (eps[2]==0xd3) && (eps[3]==0xc6))
  594.         extract_eps();
  595.     else
  596.         preview = 0;
  597.     doc = psscan(dfile);
  598.     if (doc == (struct document *)NULL) {
  599.         dfclose();
  600.         return FALSE;
  601.     }
  602.     if (eps[0] == '\004')
  603.         is_ctrld = TRUE;
  604.     if (!preview && doc->beginpreview)
  605.         preview = IDS_EPSI;
  606.     page_list.select = (BOOL *)malloc( doc->numpages * sizeof(BOOL) );
  607.     return TRUE;
  608. }
  609.  
  610.  
  611.  
  612. /* Copy specified pages from dfile to file f */
  613. void
  614. dsc_getpages(FILE *f, int first, int last)
  615. {
  616. int i, page;
  617.     for (i=first-1; i<last; i++) {
  618.         page = map_page(i);
  619.         if (doc->pages) {
  620.             fprintf(f,"(Page: %s %d\\n) print flush\r\n", doc->pages[page].label ? doc->pages[page].label : " ", page+1);
  621.         pscopy(dfile, f, doc->pages[page].begin, doc->pages[page].end);
  622.         }
  623.         else {
  624.             fprintf(f,"(Page: %d\\n) print flush\r\n",page); 
  625.         pscopy(dfile, f, doc->endsetup, doc->endtrailer);
  626.         }
  627.     }
  628. }
  629.  
  630.  
  631. /* Copy dsc header to file f */
  632. void
  633. dsc_header(FILE *f)
  634. {
  635. char *p;
  636.     fputs("(Displaying ",f);
  637.     for (p=dfname; *p; p++) {
  638.         if (*p != '\\')
  639.         fputc(*p,f);
  640.         else
  641.         fputc('/',f);
  642.     }
  643.     fputs("\\n) print flush\r\n",f);
  644.     pscopy(dfile, f, doc->beginheader, doc->endheader);
  645.     pscopy(dfile, f, doc->begindefaults, doc->enddefaults);
  646.     pscopy(dfile, f, doc->beginprolog, doc->endprolog);
  647.     pscopy(dfile, f, doc->beginsetup, doc->endsetup);
  648. }
  649.  
  650.  
  651. /* Send commands to gswin to display page */
  652. void
  653. dsc_dopage(void)
  654. {
  655.     info_wait(TRUE);
  656.     if (!saved) {
  657.            fix_orientation(cfile);
  658.            dsc_header(cfile);
  659.     }
  660.     dsc_getpages(cfile,pagenum,pagenum);
  661.     pipeflush();
  662. }
  663.  
  664. /* skip pages */
  665. void
  666. dsc_skip(int skip)
  667. {
  668.     if ( (skip == 0)
  669.       || ((skip > 0) && (pagenum == doc->numpages))
  670.       || ((skip < 0) && (pagenum == 1))
  671.       || (doc->numpages == 0) ) {
  672.         play_sound(SOUND_NOPAGE);
  673.         info_wait(FALSE);
  674.         return;
  675.     }
  676.     pagenum += skip;
  677.     if (pagenum > (int)doc->numpages)
  678.          pagenum = doc->numpages;
  679.     if (pagenum < 1)
  680.         pagenum = 1;
  681.     info_wait(TRUE);
  682.     if (page_ready)
  683.         next_page();
  684.     if (gswin_open())
  685.         dsc_dopage();
  686. }
  687.  
  688. /* reverse zero based page number if needed */
  689. int
  690. map_page(int page)
  691. {
  692.         if (doc->pageorder == DESCEND) 
  693.         return (doc->numpages - 1) - page;
  694.     return page;
  695. }
  696.